{
  "nbformat": 4,
  "nbformat_minor": 5,
  "metadata": {},
  "cells": [
    {
      "metadata": {},
      "source": [
        "<td>\n",
        "   <a target=\"_blank\" href=\"https://labelbox.com\" ><img src=\"https://labelbox.com/blog/content/images/2021/02/logo-v4.svg\" width=256/></a>\n",
        "</td>"
      ],
      "cell_type": "markdown"
    },
    {
      "metadata": {},
      "source": [
        "<td>\n",
        "<a href=\"https://colab.research.google.com/github/Labelbox/labelbox-python/blob/master/examples/annotation_import/tiled.ipynb\" target=\"_blank\"><img\n",
        "src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"></a>\n",
        "</td>\n",
        "\n",
        "<td>\n",
        "<a href=\"https://github.com/Labelbox/labelbox-python/tree/master/examples/annotation_import/tiled.ipynb\" target=\"_blank\"><img\n",
        "src=\"https://img.shields.io/badge/GitHub-100000?logo=github&logoColor=white\" alt=\"GitHub\"></a>\n",
        "</td>"
      ],
      "cell_type": "markdown"
    },
    {
      "metadata": {},
      "source": [
        "# Tiled Imagery Annotation Import\n",
        "* This notebook will provide examples of each supported annotation type for tiled imagery assets, and also cover MAL and Label Import methods:\n",
        "\n",
        "Supported annotations that can be uploaded through the SDK: \n",
        "  * Point \n",
        "  * Polygon\n",
        "  * Bounding Box \n",
        "  * Classification radio \n",
        "  * Classification checklist \n",
        "  * Classification free-form text\n",
        "\n",
        "**Not** supported:\n",
        "  * Segmentation mask\n",
        "\n",
        "\n",
        "MAL and Label Import: \n",
        "\n",
        "* Model-assisted labeling - used to provide pre-annotated data for your labelers. This will enable a reduction in the total amount of time to properly label your assets. Model-assisted labeling does not submit the labels automatically, and will need to be reviewed by a labeler for submission.\n",
        "* Label Import - used to provide ground truth labels. These can in turn be used and compared against prediction labels, or used as benchmarks to see how your labelers are doing.\n",
        "\n",
        "For information on what types of annotations are supported per data type, refer to this documentation:\n",
        "    * https://docs.labelbox.com/docs/model-assisted-labeling#option-1-import-via-python-annotation-types-recommended"
      ],
      "cell_type": "markdown"
    },
    {
      "metadata": {},
      "source": [
        "Notes:\n",
        " * This notebook uses the Slippy Maps format\n",
        " * If you are importing more than 1,000 annotations at a time, consider submitting separate jobs, as they can take longer than other annotation types to import.\n",
        " * Wait until the import job is complete before opening the Editor to make sure all annotations are imported properly.\n",
        " * You may need to refresh your browser in order to see the results of the import job."
      ],
      "cell_type": "markdown"
    },
    {
      "metadata": {},
      "source": [
        "### Setup"
      ],
      "cell_type": "markdown"
    },
    {
      "metadata": {},
      "source": [
        "!pip install -q 'labelbox[data]'"
      ],
      "cell_type": "code",
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {},
      "source": [
        "\n",
        "import uuid\n",
        "import numpy as np\n",
        "import cv2\n",
        "import labelbox as lb\n",
        "import labelbox.types as lb_types\n",
        "\n"
      ],
      "cell_type": "code",
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {},
      "source": [
        "### Replace with your API key\n",
        "Guides on [Create an API key](https://docs.labelbox.com/docs/create-an-api-key)"
      ],
      "cell_type": "markdown"
    },
    {
      "metadata": {},
      "source": [
        "API_KEY = \"\"\n",
        "client = lb.Client(API_KEY)"
      ],
      "cell_type": "code",
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {},
      "source": [
        "## Supported annotations for tiled imagery"
      ],
      "cell_type": "markdown"
    },
    {
      "metadata": {},
      "source": [
        "### Supported Python annotation types and NDJSON "
      ],
      "cell_type": "markdown"
    },
    {
      "metadata": {},
      "source": [
        "####### Point #######\n",
        "\n",
        "# Python Annotation\n",
        "point_annotation = lb_types.ObjectAnnotation(\n",
        "  name = \"point_geo\",\n",
        "  value = lb_types.Point(x=-99.20647859573366, y=19.40018029091072),\n",
        ")\n",
        "\n",
        "# NDJSON\n",
        "point_annotation_ndjson = {\n",
        "    \"name\": \"point_geo\",\n",
        "    \"point\": {\n",
        "         \"x\": -99.20647859573366,\n",
        "         \"y\": 19.40018029091072\n",
        "     }\n",
        "}"
      ],
      "cell_type": "code",
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {},
      "source": [
        "####### Polyline #######\n",
        "# Coordinates\n",
        "coords = [\n",
        "            [\n",
        "                -99.20842051506044,\n",
        "                19.40032196622975\n",
        "            ],\n",
        "            [\n",
        "                -99.20809864997865,\n",
        "                19.39758963475322\n",
        "            ],\n",
        "            [\n",
        "                -99.20758366584778,\n",
        "                19.39776167179227\n",
        "            ],\n",
        "            [\n",
        "                -99.20728325843811,\n",
        "                19.3973265189299\n",
        "            ]\n",
        "        ]\n",
        "\n",
        "line_points = []\n",
        "line_points_ndjson = []\n",
        "\n",
        "for sub in coords: \n",
        "  line_points.append(lb_types.Point(x=sub[0], y=sub[1]))\n",
        "  line_points_ndjson.append({\"x\":sub[0], \"y\":sub[1]})\n",
        "\n",
        "# Python Annotation \n",
        "polyline_annotation = lb_types.ObjectAnnotation(\n",
        "  name = \"polyline_geo\",\n",
        "  value = lb_types.Line(points=line_points),\n",
        ")\n",
        "\n",
        "# NDJSON \n",
        "polyline_annotation_ndjson = {\n",
        "    \"name\": \"polyline_geo\",\n",
        "    \"line\": line_points_ndjson\n",
        "}"
      ],
      "cell_type": "code",
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {},
      "source": [
        "####### Polygon #######\n",
        "# Coordinates in the desired EPSG coordinate system\n",
        "coords_polygon = [\n",
        "    [\n",
        "        -99.21042680740356,\n",
        "        19.40036244486966\n",
        "    ],\n",
        "    [\n",
        "        -99.2104160785675,\n",
        "        19.40017017124035\n",
        "    ],\n",
        "    [\n",
        "        -99.2103409767151,\n",
        "        19.400008256428897\n",
        "    ],\n",
        "    [\n",
        "        -99.21014785766603,\n",
        "        19.400008256428897\n",
        "    ],\n",
        "    [\n",
        "        -99.21019077301027,\n",
        "        19.39983622176518\n",
        "    ],\n",
        "    [\n",
        "        -99.21022295951845,\n",
        "        19.399674306621385\n",
        "    ],\n",
        "    [\n",
        "        -99.21029806137086,\n",
        "        19.39951239131646\n",
        "    ],\n",
        "    [\n",
        "        -99.2102873325348,\n",
        "        19.399340356128437\n",
        "    ],\n",
        "    [\n",
        "        -99.21025514602663,\n",
        "        19.399117722085677\n",
        "    ],\n",
        "    [\n",
        "        -99.21024441719057,\n",
        "        19.39892544698541\n",
        "    ],\n",
        "    [\n",
        "        -99.2102336883545,\n",
        "        19.39874329141769\n",
        "    ],\n",
        "    [\n",
        "        -99.21021223068239,\n",
        "        19.398561135646027\n",
        "    ],\n",
        "    [\n",
        "        -99.21018004417421,\n",
        "        19.398399219233365\n",
        "    ],\n",
        "    [\n",
        "        -99.21011567115785,\n",
        "        19.39822718286836\n",
        "    ],\n",
        "    [\n",
        "        -99.20992255210878,\n",
        "        19.398136104719125\n",
        "    ],\n",
        "    [\n",
        "        -99.20974016189577,\n",
        "        19.398085505725305\n",
        "    ],\n",
        "    [\n",
        "        -99.20957922935487,\n",
        "        19.398004547302467\n",
        "    ],\n",
        "    [\n",
        "        -99.20939683914186,\n",
        "        19.39792358883935\n",
        "    ],\n",
        "    [\n",
        "        -99.20918226242067,\n",
        "        19.39786286996558\n",
        "    ],\n",
        "    [\n",
        "        -99.20899987220764,\n",
        "        19.397822390703805\n",
        "    ],\n",
        "    [\n",
        "        -99.20891404151918,\n",
        "        19.397994427496787\n",
        "    ],\n",
        "    [\n",
        "        -99.20890331268312,\n",
        "        19.398176583902874\n",
        "    ],\n",
        "    [\n",
        "        -99.20889258384706,\n",
        "        19.398368859888045\n",
        "    ],\n",
        "    [\n",
        "        -99.20889258384706,\n",
        "        19.398540896103246\n",
        "    ],\n",
        "    [\n",
        "        -99.20890331268312,\n",
        "        19.39872305189756\n",
        "    ],\n",
        "    [\n",
        "        -99.20889258384706,\n",
        "        19.39890520748796\n",
        "    ],\n",
        "    [\n",
        "        -99.20889258384706,\n",
        "        19.39907724313608\n",
        "    ],\n",
        "    [\n",
        "        -99.20889258384706,\n",
        "        19.399259398329956\n",
        "    ],\n",
        "    [\n",
        "        -99.20890331268312,\n",
        "        19.399431433603585\n",
        "    ],\n",
        "    [\n",
        "        -99.20890331268312,\n",
        "        19.39961358840092\n",
        "    ],\n",
        "    [\n",
        "        -99.20890331268312,\n",
        "        19.399785623300048\n",
        "    ],\n",
        "    [\n",
        "        -99.20897841453552,\n",
        "        19.399937418648214\n",
        "    ],\n",
        "    [\n",
        "        -99.20919299125673,\n",
        "        19.399937418648214\n",
        "    ],\n",
        "    [\n",
        "        -99.2093861103058,\n",
        "        19.39991717927664\n",
        "    ],\n",
        "    [\n",
        "        -99.20956850051881,\n",
        "        19.39996777770086\n",
        "    ],\n",
        "    [\n",
        "        -99.20961141586305,\n",
        "        19.40013981222548\n",
        "    ],\n",
        "    [\n",
        "        -99.20963287353517,\n",
        "        19.40032196622975\n",
        "    ],\n",
        "    [\n",
        "        -99.20978307724,\n",
        "        19.4004130431554\n",
        "    ],\n",
        "    [\n",
        "        -99.20996546745302,\n",
        "        19.40039280384301\n",
        "    ],\n",
        "    [\n",
        "        -99.21019077301027,\n",
        "        19.400372564528084\n",
        "    ],\n",
        "    [\n",
        "        -99.21042680740356,\n",
        "        19.40036244486966\n",
        "    ]\n",
        "    \n",
        "]\n",
        "\n",
        "polygon_points = []\n",
        "polygon_points_ndjson = []\n",
        "\n",
        "for sub in coords_polygon: \n",
        "  polygon_points.append(lb_types.Point(x=sub[0], y=sub[1]))\n",
        "  polygon_points_ndjson.append({\"x\":sub[0], \"y\":sub[1]})\n",
        "\n",
        "# Python Annotation \n",
        "polygon_annotation = lb_types.ObjectAnnotation(\n",
        "  name = \"polygon_geo\",\n",
        "  value = lb_types.Polygon(points=polygon_points),\n",
        ")\n",
        "\n",
        "# NDJSON \n",
        "polygon_annotation_ndjson = {\n",
        "    \"name\": \"polygon_geo\",\n",
        "    \"polygon\": polygon_points_ndjson\n",
        "}"
      ],
      "cell_type": "code",
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {},
      "source": [
        "####### Bounding Box #######\n",
        "coord_object =  {\n",
        "    \"coordinates\" : [[\n",
        "            [\n",
        "                -99.20746564865112,\n",
        "                19.39799442829336\n",
        "            ],\n",
        "            [\n",
        "                -99.20746564865112,\n",
        "                19.39925939999194\n",
        "            ],\n",
        "            [\n",
        "                -99.20568466186523,\n",
        "                19.39925939999194\n",
        "            ],\n",
        "            [\n",
        "                -99.20568466186523,\n",
        "                19.39799442829336\n",
        "            ],\n",
        "            [\n",
        "                -99.20746564865112,\n",
        "                19.39799442829336\n",
        "            ]\n",
        "        ]]\n",
        "}\n",
        "      \n",
        "\n",
        "\n",
        "\n",
        "bbox_top_left = lb_types.Point(x= -99.20746564865112, y=19.39799442829336)\n",
        "bbox_bottom_right = lb_types.Point(x=-99.20568466186523, y=19.39925939999194)\n",
        "\n",
        "# Python Annotation\n",
        "bbox_annotation = lb_types.ObjectAnnotation(\n",
        "  name = \"bbox_geo\",\n",
        "  value = lb_types.Rectangle(start=bbox_top_left, end=bbox_bottom_right)\n",
        ")\n",
        "\n",
        "\n",
        "# NDJSON\n",
        "bbox_annotation_ndjson = {\n",
        "    \"name\" : \"bbox_geo\",\n",
        "    \"bbox\" : {\n",
        "        'top': coord_object[\"coordinates\"][0][1][1],\n",
        "        'left': coord_object[\"coordinates\"][0][1][0],\n",
        "        'height': coord_object[\"coordinates\"][0][3][1] - coord_object[\"coordinates\"][0][1][1],        \n",
        "        'width': coord_object[\"coordinates\"][0][3][0] - coord_object[\"coordinates\"][0][1][0]\n",
        "    }\n",
        "}\n"
      ],
      "cell_type": "code",
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {},
      "source": [
        "####### Classification - radio (single choice) #######\n",
        "\n",
        "# Python Annotation \n",
        "radio_annotation = lb_types.ClassificationAnnotation(\n",
        "    name=\"radio_question_geo\", \n",
        "    value=lb_types.Radio(answer=lb_types.ClassificationAnswer(name=\"first_radio_answer\"))\n",
        ")\n",
        "\n",
        "\n",
        "# NDJSON \n",
        "radio_annotation_ndjson = {\n",
        "    \"name\": \"radio_question_geo\",\n",
        "    \"answer\": { \"name\": \"first_radio_answer\"}\n",
        "}"
      ],
      "cell_type": "code",
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {},
      "source": [
        "####### Classification - Checklist (multi-choice) #######\n",
        "\n",
        "coord_object_checklist = {\n",
        "    \"coordinates\": [\n",
        "       [\n",
        "            [\n",
        "                -99.210266,\n",
        "                19.39540372195134\n",
        "            ],\n",
        "            [\n",
        "                -99.210266,\n",
        "                19.396901\n",
        "            ],\n",
        "            [\n",
        "                -99.20621067903966,\n",
        "                19.396901\n",
        "            ],\n",
        "            [\n",
        "                -99.20621067903966,\n",
        "                19.39540372195134\n",
        "            ],\n",
        "            [\n",
        "                -99.210266,\n",
        "                19.39540372195134\n",
        "            ]\n",
        "      ]\n",
        "    ]          \n",
        "}\n",
        "\n",
        "# Python Annotation\n",
        "bbox_with_checklist_subclass = lb_types.ObjectAnnotation(\n",
        "    name=\"bbox_checklist_geo\",\n",
        "    value=lb_types.Rectangle(\n",
        "        start=lb_types.Point(x=-99.210266, y=19.39540372195134), # Top left\n",
        "        end=lb_types.Point(x=-99.20621067903966, y=19.396901), # Bottom right\n",
        "    ),\n",
        "    classifications=[\n",
        "        lb_types.ClassificationAnnotation(\n",
        "            name=\"checklist_class_name\",\n",
        "            value=lb_types.Checklist(\n",
        "                answer=[lb_types.ClassificationAnswer(name=\"first_checklist_answer\")]\n",
        "            )\n",
        "        )\n",
        "    ]\n",
        ")\n",
        "\n",
        "\n",
        "# NDJSON \n",
        "bbox_with_checklist_subclass_ndjson = {\n",
        "    \"name\": \"bbox_checklist_geo\", \n",
        "    \"classifications\": [{\n",
        "        \"name\": \"checklist_class_name\",\n",
        "        \"answer\": [\n",
        "            { \"name\":\"first_checklist_answer\" }\n",
        "        ]   \n",
        "    }],\n",
        "    \"bbox\": {\n",
        "        'top': coord_object_checklist[\"coordinates\"][0][1][1],\n",
        "        'left': coord_object_checklist[\"coordinates\"][0][1][0],\n",
        "        'height': coord_object_checklist[\"coordinates\"][0][3][1] - coord_object_checklist[\"coordinates\"][0][1][1],        \n",
        "        'width': coord_object_checklist[\"coordinates\"][0][3][0] - coord_object_checklist[\"coordinates\"][0][1][0]\n",
        "    }\n",
        "}"
      ],
      "cell_type": "code",
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {},
      "source": [
        "####### Classification free form text with bbox #######\n",
        "\n",
        "coord_object_text ={\n",
        "    \"coordinates\": [\n",
        "      [\n",
        "        [\n",
        "            -99.21019613742828,\n",
        "            19.397447957052933\n",
        "        ],\n",
        "        [\n",
        "            -99.21019613742828,\n",
        "            19.39772119262215\n",
        "        ],\n",
        "        [\n",
        "            -99.20986354351044,\n",
        "            19.39772119262215\n",
        "        ],\n",
        "        [\n",
        "            -99.20986354351044,\n",
        "            19.397447957052933\n",
        "        ],\n",
        "        [\n",
        "            -99.21019613742828,\n",
        "            19.397447957052933\n",
        "        ]\n",
        "      ]\n",
        "    ]\n",
        "}\n",
        "# Python Annotation\n",
        "bbox_with_free_text_subclass = lb_types.ObjectAnnotation(\n",
        "    name=\"bbox_text_geo\",\n",
        "    value=lb_types.Rectangle(\n",
        "        start=lb_types.Point(x=-99.21019613742828, y=19.397447957052933), # Top left\n",
        "        end=lb_types.Point(x=-99.20986354351044, y=19.39772119262215), # Bottom right\n",
        "    ),\n",
        "    classifications=[\n",
        "        lb_types.ClassificationAnnotation(\n",
        "            name=\"free_text_geo\",\n",
        "            value=lb_types.Text(answer=\"sample text\")\n",
        "        )\n",
        "    ]\n",
        ")\n",
        "\n",
        "# NDJSON \n",
        "bbox_with_free_text_subclass_ndjson = {\n",
        "    \"name\":\"bbox_text_geo\",\n",
        "    \"classifications\": [{\n",
        "        \"name\": \"free_text_geo\",\n",
        "        \"answer\": \"sample text\"\n",
        "    }],\n",
        "    \"bbox\": {\n",
        "        'top': coord_object_text[\"coordinates\"][0][1][1],\n",
        "        'left': coord_object_text[\"coordinates\"][0][1][0],\n",
        "        'height': coord_object_text[\"coordinates\"][0][3][1] - coord_object_text[\"coordinates\"][0][1][1],        \n",
        "        'width': coord_object_text[\"coordinates\"][0][3][0] - coord_object_text[\"coordinates\"][0][1][0]\n",
        "    }\n",
        "}"
      ],
      "cell_type": "code",
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {},
      "source": [
        "####### Classification - Checklist (multi-choice) #######\n",
        "\n",
        "# Python Annotation\n",
        "checklist_annotation = lb_types.ClassificationAnnotation(\n",
        "    name=\"checklist_question_geo\",\n",
        "    value=lb_types.Checklist(answer = [\n",
        "        lb_types.ClassificationAnswer(name = \"first_checklist_answer\"),\n",
        "        lb_types.ClassificationAnswer(name = \"second_checklist_answer\"),\n",
        "        lb_types.ClassificationAnswer(name = \"third_checklist_answer\")\n",
        "    ])\n",
        "  )\n",
        "\n",
        "\n",
        "\n",
        "# NDJSON\n",
        "checklist_annotation_ndjson = {\n",
        "  'name': 'checklist_question_geo',\n",
        "  'answer': [\n",
        "    {'name': 'first_checklist_answer'},\n",
        "    {'name': 'second_checklist_answer'},\n",
        "    {'name': 'third_checklist_answer'},\n",
        "  ]\n",
        "}"
      ],
      "cell_type": "code",
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {},
      "source": [
        "########## Classification - Radio and Checklist (with subclassifications)  ##########\n",
        "\n",
        "nested_radio_annotation = lb_types.ClassificationAnnotation(\n",
        "  name=\"nested_radio_question\",\n",
        "  value=lb_types.Radio(\n",
        "    answer=lb_types.ClassificationAnswer(\n",
        "      name=\"first_radio_answer\",\n",
        "      classifications=[\n",
        "        lb_types.ClassificationAnnotation(\n",
        "          name=\"sub_radio_question\",\n",
        "          value=lb_types.Radio(\n",
        "            answer=lb_types.ClassificationAnswer(\n",
        "              name=\"first_sub_radio_answer\"\n",
        "            )\n",
        "          )\n",
        "        )\n",
        "      ]\n",
        "    )\n",
        "  )\n",
        ")\n",
        "# NDJSON\n",
        "nested_radio_annotation_ndjson= {\n",
        "  \"name\": \"nested_radio_question\",\n",
        "  \"answer\": {\n",
        "      \"name\": \"first_radio_answer\",\n",
        "      \"classifications\": [{\n",
        "          \"name\":\"sub_radio_question\",\n",
        "          \"answer\": { \"name\" : \"first_sub_radio_answer\"}\n",
        "        }]\n",
        "    }\n",
        "}\n",
        "\n",
        "nested_checklist_annotation = lb_types.ClassificationAnnotation(\n",
        "  name=\"nested_checklist_question\",\n",
        "  value=lb_types.Checklist(\n",
        "    answer=[lb_types.ClassificationAnswer(\n",
        "      name=\"first_checklist_answer\",\n",
        "      classifications=[\n",
        "        lb_types.ClassificationAnnotation(\n",
        "          name=\"sub_checklist_question\",\n",
        "          value=lb_types.Checklist(\n",
        "            answer=[lb_types.ClassificationAnswer(\n",
        "            name=\"first_sub_checklist_answer\"\n",
        "          )]\n",
        "        ))\n",
        "      ]\n",
        "    )]\n",
        "  )\n",
        ")\n",
        "nested_checklist_annotation_ndjson = {\n",
        "  \"name\": \"nested_checklist_question\",\n",
        "  \"answer\": [{\n",
        "      \"name\": \"first_checklist_answer\", \n",
        "      \"classifications\" : [\n",
        "        {\n",
        "          \"name\": \"sub_checklist_question\", \n",
        "          \"answer\": {\"name\": \"first_sub_checklist_answer\"}\n",
        "        }          \n",
        "      ]         \n",
        "  }]\n",
        "}"
      ],
      "cell_type": "code",
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {},
      "source": [
        "## Upload Annotations - putting it all together\n"
      ],
      "cell_type": "markdown"
    },
    {
      "metadata": {},
      "source": [
        "### Step 1: Import data rows into Catalog"
      ],
      "cell_type": "markdown"
    },
    {
      "metadata": {},
      "source": [
        "\n",
        "top_left_bound = lb_types.Point(x=-99.21052827588443, y=19.400498983095076)\n",
        "bottom_right_bound = lb_types.Point(x=-99.20534818927473, y=19.39533555271248)\n",
        "\n",
        "epsg = lb_types.EPSG.EPSG4326\n",
        "bounds = lb_types.TiledBounds(epsg=epsg, bounds=[top_left_bound, bottom_right_bound])\n",
        "global_key = \"mexico_city\"\n",
        "\n",
        "tile_layer = lb_types.TileLayer(\n",
        "    url=\"https://s3-us-west-1.amazonaws.com/lb-tiler-layers/mexico_city/{z}/{x}/{y}.png\"\n",
        ")\n",
        "\n",
        "tiled_image_data = lb_types.TiledImageData(tile_layer=tile_layer,\n",
        "                                  tile_bounds=bounds,\n",
        "                                  zoom_levels=[17, 23])\n",
        "\n",
        "asset = {\n",
        "    \"row_data\": tiled_image_data.asdict(),\n",
        "    \"global_key\": global_key,\n",
        "    \"media_type\": \"TMS_GEO\"\n",
        "}\n",
        "\n",
        "dataset = client.create_dataset(name=\"geo_demo_dataset\")\n",
        "task= dataset.create_data_rows([asset])\n",
        "print(\"Errors:\",task.errors)\n",
        "print(\"Failed data rows:\", task.failed_data_rows)"
      ],
      "cell_type": "code",
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {},
      "source": [
        "### Step 2: Create/select an ontology\n",
        "Your project should have the correct ontology setup with all the tools and classifications supported for your annotations, and the tool names and classification instructions should match the `name` fields in your annotations to ensure the correct feature schemas are matched."
      ],
      "cell_type": "markdown"
    },
    {
      "metadata": {},
      "source": [
        "ontology_builder = lb.OntologyBuilder(\n",
        "    tools=[\n",
        "        lb.Tool(tool=lb.Tool.Type.POINT, name=\"point_geo\"),\n",
        "        lb.Tool(tool=lb.Tool.Type.LINE, name=\"polyline_geo\"),\n",
        "        lb.Tool(tool=lb.Tool.Type.POLYGON, name=\"polygon_geo\"),\n",
        "        lb.Tool(tool=lb.Tool.Type.POLYGON, name=\"polygon_geo_2\"),\n",
        "        lb.Tool(tool=lb.Tool.Type.BBOX, name=\"bbox_geo\"), \n",
        "        lb.Tool( \n",
        "          tool=lb.Tool.Type.BBOX, \n",
        "          name=\"bbox_checklist_geo\",\n",
        "          classifications=[\n",
        "                lb.Classification(\n",
        "                    class_type=lb.Classification.Type.CHECKLIST,\n",
        "                    name=\"checklist_class_name\",\n",
        "                    options=[\n",
        "                      lb.Option(value=\"first_checklist_answer\")\n",
        "                    ]\n",
        "                ),\n",
        "            ]\n",
        "          ),\n",
        "        lb.Tool( \n",
        "          tool=lb.Tool.Type.BBOX, \n",
        "          name=\"bbox_text_geo\",\n",
        "          classifications=[\n",
        "                lb.Classification(\n",
        "                    class_type=lb.Classification.Type.TEXT,\n",
        "                    name=\"free_text_geo\"\n",
        "                ),\n",
        "            ]\n",
        "          )    \n",
        "      ],\n",
        "      classifications = [\n",
        "          lb.Classification(\n",
        "              class_type=lb.Classification.Type.CHECKLIST, \n",
        "              name=\"checklist_question_geo\",\n",
        "              options=[\n",
        "                  lb.Option(value=\"first_checklist_answer\"),\n",
        "                  lb.Option(value=\"second_checklist_answer\"), \n",
        "                  lb.Option(value=\"third_checklist_answer\")\n",
        "              ]\n",
        "          ), \n",
        "          lb.Classification(\n",
        "              class_type=lb.Classification.Type.RADIO, \n",
        "              name=\"radio_question_geo\",\n",
        "              options=[\n",
        "                  lb.Option(value=\"first_radio_answer\")\n",
        "              ]\n",
        "          ),\n",
        "          \n",
        "        lb.Classification( \n",
        "          class_type=lb.Classification.Type.RADIO, \n",
        "          name=\"nested_radio_question\", \n",
        "          options=[\n",
        "            lb.Option(value=\"first_radio_answer\",\n",
        "              options=[\n",
        "                  lb.Classification(\n",
        "                    class_type=lb.Classification.Type.RADIO,\n",
        "                    name=\"sub_radio_question\",\n",
        "                    options=[\n",
        "                      lb.Option(value=\"first_sub_radio_answer\")\n",
        "                    ]\n",
        "                ),\n",
        "              ]\n",
        "            ),\n",
        "          ], \n",
        "        ),\n",
        "        lb.Classification(\n",
        "          class_type=lb.Classification.Type.CHECKLIST,\n",
        "          name=\"nested_checklist_question\",\n",
        "          options=[\n",
        "              lb.Option(\"first_checklist_answer\",\n",
        "                options=[\n",
        "                  lb.Classification(\n",
        "                      class_type=lb.Classification.Type.CHECKLIST,\n",
        "                      name=\"sub_checklist_question\", \n",
        "                      options=[lb.Option(\"first_sub_checklist_answer\")]\n",
        "                  )\n",
        "              ]\n",
        "            )\n",
        "          ]\n",
        "      ) \n",
        "    ]\n",
        ")\n",
        "\n",
        "ontology = client.create_ontology(\"Ontology Geospatial Annotations\", ontology_builder.asdict(), media_type=lb.MediaType.Geospatial_Tile)"
      ],
      "cell_type": "code",
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {},
      "source": [
        "### Step 3: Create a labeling project\n",
        "Connect the ontology to the labeling project "
      ],
      "cell_type": "markdown"
    },
    {
      "metadata": {},
      "source": [
        "# Project defaults to batch mode with benchmark quality settings if this argument is not provided\n",
        "# Queue mode will be deprecated once dataset mode is deprecated\n",
        "\n",
        "project = client.create_project(name=\"Geospatial Project Demo\",\n",
        "                                    media_type=lb.MediaType.Geospatial_Tile)\n",
        "\n",
        "\n",
        "project.setup_editor(ontology)\n"
      ],
      "cell_type": "code",
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {},
      "source": [
        "### Step 4: Send a batch of data rows to the project "
      ],
      "cell_type": "markdown"
    },
    {
      "metadata": {},
      "source": [
        "# Setup Batches and Ontology\n",
        "\n",
        "# Create a batch to send to your MAL project\n",
        "batch = project.create_batch(\n",
        "  \"first-batch-geo-demo\", # Each batch in a project must have a unique name\n",
        "  global_keys=[global_key], # Paginated collection of data row objects, list of data row ids or global keys\n",
        "  priority=5 # priority between 1(Highest) - 5(lowest)\n",
        ")\n",
        "\n",
        "print(\"Batch: \", batch)"
      ],
      "cell_type": "code",
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {},
      "source": [
        "### Step 5: Create the annotations payload \n",
        "Create the annotations payload using the snippets of code above\n",
        "\n",
        "Labelbox support two formats for the annotations payload: NDJSON and Python Annotation types. Both are described below. \n"
      ],
      "cell_type": "markdown"
    },
    {
      "metadata": {},
      "source": [
        "#### Python annotations\n",
        "Here we create the complete label ndjson payload of annotations only using python annotation format. There is one annotation for each reference to an annotation that we created on ***Supported Python annotation types and NDJSON*** section."
      ],
      "cell_type": "markdown"
    },
    {
      "metadata": {},
      "source": [
        " ## Lets create another polygon annotation with python annotation tools that draws the image using cv2 python libraries\n",
        "\n",
        "hsv = cv2.cvtColor(tiled_image_data.value, cv2.COLOR_RGB2HSV)\n",
        "mask = cv2.inRange(hsv, (25, 50, 25), (100, 150, 255))\n",
        "kernel = np.ones((15, 20), np.uint8)\n",
        "mask = cv2.erode(mask, kernel)\n",
        "mask = cv2.dilate(mask, kernel)\n",
        "mask_annotation = lb_types.MaskData.from_2D_arr(mask)\n",
        "mask_data = lb_types.Mask(mask=mask_annotation, color=[255, 255, 255])\n",
        "h, w, _ = tiled_image_data.value.shape\n",
        "pixel_bounds = lb_types.TiledBounds(epsg=lb_types.EPSG.SIMPLEPIXEL,\n",
        "                          bounds=[lb_types.Point(x=0, y=0),\n",
        "                                  lb_types.Point(x=w, y=h)])\n",
        "transformer = lb_types.EPSGTransformer.create_pixel_to_geo_transformer(\n",
        "    src_epsg=pixel_bounds.epsg,\n",
        "    pixel_bounds=pixel_bounds,\n",
        "    geo_bounds=tiled_image_data.tile_bounds,\n",
        "    zoom=20)\n",
        "pixel_polygons = mask_data.shapely.simplify(3)\n",
        "list_of_polygons = [transformer(lb_types.Polygon.from_shapely(p)) for p in pixel_polygons.geoms]\n",
        "polygon_annotation_two = lb_types.ObjectAnnotation(value=list_of_polygons[0], name=\"polygon_geo_2\")\n"
      ],
      "cell_type": "code",
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {},
      "source": [
        "labels =[]\n",
        "labels.append(\n",
        "    lb_types.Label(\n",
        "        data=lb_types.TiledImageData(\n",
        "            global_key=global_key,\n",
        "            tile_layer=tile_layer,\n",
        "            tile_bounds=bounds,\n",
        "            zoom_levels=[12, 20]\n",
        "        ),\n",
        "        annotations = [\n",
        "            point_annotation,\n",
        "            polyline_annotation,\n",
        "            polygon_annotation,\n",
        "            bbox_annotation,\n",
        "            radio_annotation,\n",
        "            bbox_with_checklist_subclass,  \n",
        "            bbox_with_free_text_subclass,\n",
        "            checklist_annotation,\n",
        "            polygon_annotation_two, \n",
        "            nested_checklist_annotation, \n",
        "            nested_radio_annotation\n",
        "        ]\n",
        "    )\n",
        ")"
      ],
      "cell_type": "code",
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {},
      "source": [
        "### NDJSON annotations\n",
        "Here we create the complete label NDJSON payload of annotations only using NDJSON format. There is one annotation for each reference to an annotation that we created on *** Supported Python annotation types and NDJSON *** section."
      ],
      "cell_type": "markdown"
    },
    {
      "metadata": {},
      "source": [
        "label_ndjson = []\n",
        "\n",
        "for annotations in [point_annotation_ndjson,\n",
        "                    polyline_annotation_ndjson,\n",
        "                    polygon_annotation_ndjson,\n",
        "                    bbox_annotation_ndjson,\n",
        "                    radio_annotation_ndjson,\n",
        "                    bbox_with_checklist_subclass_ndjson,  \n",
        "                    bbox_with_free_text_subclass_ndjson,\n",
        "                    checklist_annotation_ndjson,\n",
        "                    nested_checklist_annotation_ndjson,\n",
        "                    nested_radio_annotation_ndjson\n",
        "                    ]:\n",
        "  annotations.update({\n",
        "      'dataRow': {\n",
        "          'globalKey': global_key\n",
        "      }\n",
        "  })\n",
        "  label_ndjson.append(annotations)\n",
        "  "
      ],
      "cell_type": "code",
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {},
      "source": [
        "### Step 6: Upload annotations to a project as pre-labels or complete labels\n"
      ],
      "cell_type": "markdown"
    },
    {
      "metadata": {},
      "source": [
        "#### Model-Assisted Labeling (MAL)\n",
        "For the purpose of this tutorial only run one of the label_ndjosn  annotation type tools at the time (NDJSON or Annotation types). Delete the previous labels before uploading labels that use the 2nd method (ndjson)"
      ],
      "cell_type": "markdown"
    },
    {
      "metadata": {},
      "source": [
        "# Upload MAL label for this data row in project\n",
        "upload_job = lb.MALPredictionImport.create_from_objects(\n",
        "    client = client, \n",
        "    project_id = project.uid, \n",
        "    name=\"mal_import_job\"+str(uuid.uuid4()), \n",
        "    predictions=labels)\n",
        "\n",
        "upload_job.wait_until_done();\n",
        "print(\"Errors:\", upload_job.errors)\n",
        "print(\"Status of uploads: \", upload_job.statuses)"
      ],
      "cell_type": "code",
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {},
      "source": [
        "#### Label Import"
      ],
      "cell_type": "markdown"
    },
    {
      "metadata": {},
      "source": [
        "# Upload label for this data row in project \n",
        "upload_job = lb.LabelImport.create_from_objects(\n",
        "    client = client, \n",
        "    project_id = project.uid, \n",
        "    name=\"label_geo_import_job\"+str(uuid.uuid4()),  \n",
        "    labels=labels)\n",
        "\n",
        "upload_job.wait_until_done();\n",
        "print(\"Errors:\", upload_job.errors)\n",
        "print(\"Status of uploads: \", upload_job.statuses)"
      ],
      "cell_type": "code",
      "outputs": [],
      "execution_count": null
    },
    {
      "metadata": {},
      "source": [
        "### Optional deletions for cleanup"
      ],
      "cell_type": "markdown"
    },
    {
      "metadata": {},
      "source": [
        "\n",
        "# project.delete()\n",
        "# dataset.delete()"
      ],
      "cell_type": "code",
      "outputs": [],
      "execution_count": null
    }
  ]
}